package fight

import (
	"fmt"
	"idle/internal/game/attr"
	"idle/internal/game/enum"
	"idle/internal/game/skill"
	"idle/pkg/config"
	"idle/utils/randomUtils"
	"idle/utils/stringUtils"
	"log"
	"sort"
	"strconv"
	"strings"
)

const (
	defaultActionSecond = 6
	maxHitRatio         = 95
	maxBlockRatio       = 75
)

type TriggerType int

const (
	ActionTrigger     TriggerType = 1
	TargetTrigger     TriggerType = 2
	HitTrigger        TriggerType = 3
	ByHitTrigger      TriggerType = 4
	TargetDeadTrigger TriggerType = 5
	SelfDeadTrigger   TriggerType = 5
)

type FightRoom struct {
	roomID                int                //房间id
	round                 int                //回合
	fighterNextActionTime map[*Fighter]int64 //下次行动时间
	aktFighterList        []*Fighter         //进攻方战斗者
	defFighterList        []*Fighter         //防守方战斗者
	over                  bool               //战斗结束
}

func (fr *FightRoom) Init() {
	fr.fighterNextActionTime = make(map[*Fighter]int64)
	for _, fighter := range fr.aktFighterList {
		fr.fighterNextActionTime[fighter] = fr.calNextActionTime(fighter)
	}
}

func (fr *FightRoom) calNextActionTime(f *Fighter) int64 {
	gearConfig := config.GetSpeedGearConfig(f.GetAttr(attr.AttackSpeedGear))
	speed := f.GetAttr(attr.AttackSpeed)
	if !f.isAttackSpeed {
		gearConfig = config.GetSpeedGearConfig(f.GetAttr(attr.CastSpeedGear))
		speed = f.GetAttr(attr.CastSpeed)
	}
	//addSecond := stringUtils.ToFloat(gearConfig.AddSecend)
	s := defaultActionSecond*1000 - (gearConfig.AddSecend * speed)

	return 0
}

func (fr *FightRoom) fight() {
	for {
		//回合开始
		fr.roundBegin()
		if fr.over {
			break
		}
		//选择行动者
		fighter := fr.selectActionFighter()
		//选择技能
		selectSkill := fr.selectSkill(fighter)
		//选择目标
		target := fr.selectTarget(fighter)
		//触发器（行动或作为目标）
		fr.trigger(ActionTrigger, fighter, target)
		fr.trigger(TargetTrigger, fighter, target)
		//计算命中
		if fr.CalHit(fighter, target, selectSkill) {
			//计算伤害
			fr.calDamage(fighter, target, selectSkill)
			//触发器 （命中）
			fr.trigger(HitTrigger, fighter, target)
			fr.trigger(ByHitTrigger, fighter, target)
		}
		// 判断死亡
		if fr.isDead(target) {
			//触发器 （死亡）
			fr.trigger(TargetDeadTrigger, fighter, target)
			fr.trigger(SelfDeadTrigger, fighter, target)
		}

		//回合结束
		fr.roundOver()
	}

}

// 选择行动者
func (fr *FightRoom) selectActionFighter() *Fighter {
	sortSlice := make([]*Fighter, 0)
	for fighter, _ := range fr.fighterNextActionTime {
		sortSlice = append(sortSlice, fighter)
	}
	sort.SliceStable(sortSlice, func(i, j int) bool {
		f1 := sortSlice[i]
		f2 := sortSlice[j]
		//if fr.fighterNextActionTime[f1] == fr.fighterNextActionTime[f2] {
		//	_, v1 := (f1).(*hero.Hero)
		//	_, v2 := (f2).(*hero.Hero)
		//	if v1 {
		//		return true
		//	}
		//	if v2 {
		//		return false
		//	}
		//	return true
		//} else {
		//
		//}
		return fr.fighterNextActionTime[f1] < fr.fighterNextActionTime[f2]
	})
	return sortSlice[0]
}

// 随机选择一个技能
func (fr *FightRoom) selectSkill(fighter *Fighter) *skill.Skill {
	weightMap := make(map[interface{}]int)
	for i, s := range fighter.SkillList {
		weightMap[i] = 100
		if s.K {
			weightMap[i] = 150
		}
	}
	randObj := randomUtils.WeightedRandomMap(weightMap)
	index := randObj.(int)

	return fighter.SkillList[index]
}

func (fr *FightRoom) selectTarget(actionFighter *Fighter) *Fighter {
	fighterList := fr.getOtherFighterList(actionFighter)

	weightMap := make(map[interface{}]int)
	for i, fighter := range fighterList {
		if fighter.Hp <= 0 {
			continue
		}
		if fighter.isByFire {
			return fighter
		}
		weightMap[i] = 100
	}

	randObj := randomUtils.WeightedRandomMap(weightMap)
	index := randObj.(int)
	return fighterList[index]
}

func (fr *FightRoom) getOtherFighterList(actionFighter *Fighter) []*Fighter {
	for _, fighter := range fr.aktFighterList {
		if fighter == actionFighter {
			return fr.defFighterList
		}
	}
	return fr.aktFighterList
}

func (fr *FightRoom) trigger(trigger TriggerType, aktFighter *Fighter, targetFighter *Fighter) {

}

func (fr *FightRoom) CalHit(akt, target *Fighter, s *skill.Skill) bool {

	//【法术技能】是必中的
	if s.Typ == enum.SpellSkills {
		return true
	}

	//命中率% = 2 * [clvl / (clvl + mlvl)] * [att / (att + def)] * 100%。其中clvl是你的等级，mlvl是目标的等级，att是你的准确率，def是目标的防御。
	//命中率上限为95%。
	clvl := float32(akt.Lv)
	mlvl := float32(target.Lv)
	att := float32(akt.GetAttr(attr.Att))
	def := float32(target.GetAttr(attr.Def))

	hitRatio := int(2 * (clvl / (clvl + mlvl)) * (att / (att + def)) * 100)
	if hitRatio > maxHitRatio {
		hitRatio = maxHitRatio
	}

	randomHit := randomUtils.NextInt(100)
	if hitRatio < randomHit {
		log.Println(fmt.Sprintf("%s(%v/%v)使用技能 %s(%v) 攻击了%s(%v/%v) ，但被对方闪避(%v%%) ，没有造成伤害", akt.Name, akt.Hp, akt.GetAttr(attr.Hp),
			s.Name, s.SkillLv, target.Name, target.Hp, target.GetAttr(attr.Hp), hitRatio))
		return false
	}

	//格挡率% = 基础格挡率% * (dex - 15) / (clvl * 2)。其中基础格挡率是你所持盾牌的格挡率以及所有装备/技能的加成
	blockRatio := int(float32(target.GetAttr(attr.Block)) * (float32(target.GetAttr(attr.Dex)) - 15) / (float32(target.Lv) * 2))
	if blockRatio > maxBlockRatio {
		blockRatio = maxBlockRatio
	}
	randomBlock := randomUtils.NextInt(100)
	if randomBlock <= blockRatio {
		log.Println(fmt.Sprintf("%s(%v/%v)使用技能 %s(%v) 攻击了%s(%v/%v) ，但被对方格挡(%v%%) ，没有造成伤害", akt.Name, akt.Hp, akt.GetAttr(attr.Hp),
			s.Name, s.SkillLv, target.Name, target.Hp, target.GetAttr(attr.Hp), hitRatio))
		return false
	}
	return true
}

func (fr *FightRoom) calDamage(fighter *Fighter, target *Fighter, s *skill.Skill) {

}

func (fr *FightRoom) isDead(f *Fighter) bool {
	return f.Hp <= 0
}

func (fr *FightRoom) roundOver() {
	over, win := fr.checkOver()
	if !over {
		fr.round++
	} else {
		//结算
		fr.over = true
		log.Print("战斗结束，战斗结果：", win)
	}
}

func (fr *FightRoom) roundBegin() {
	// 第一回合
	if fr.round == 0 {

	}
}

func (fr *FightRoom) checkOver() (isOver, isWin bool) {
	allAktDead := true
	for _, fighter := range fr.aktFighterList {
		if !fr.isDead(fighter) {
			allAktDead = false
			break
		}
	}
	if allAktDead {
		return true, false
	}
	allDefDead := true
	for _, fighter := range fr.defFighterList {
		if !fr.isDead(fighter) {
			allDefDead = false
			break
		}
	}
	if allDefDead {
		return true, true
	}
	return false, false
}
